//////////////////////////////////////
// Fast Container Library           //
// MIT License - Copyright (c) 2012 //
//////////////////////////////////////

#pragma once

#include "common.h"
#include "iterator_traits.h"


//std iterator compatability
namespace std { struct random_access_iterator_tag; }


FC_NAMESPACE_BEGIN


template <class T>
class reverse_iterator
{
public:
	typedef typename iterator_traits<T>::iterator_category	iterator_category;
	typedef typename iterator_traits<T>::iterator_type		iterator_type;
	typedef typename iterator_traits<T>::value_type			value_type;
	typedef typename iterator_traits<T>::pointer			pointer;
	typedef typename iterator_traits<T>::reference			reference;
	typedef typename iterator_traits<T>::difference_type	difference_type;
	typedef reverse_iterator<T>								this_type;

	reverse_iterator() : ptr() {}
	explicit reverse_iterator( const T& p ) : ptr(p) {}
	reverse_iterator( const this_type& r ) : ptr(r.ptr) {}

	T base() const { return ptr; }

	pointer	operator ->() const { T temp(ptr); return &*(--temp); }
	reference operator *() const { T temp(ptr); return *(--temp); }
	reference operator []( difference_type i ) const { return *(ptr + i); } 

	this_type& operator ++() { --ptr; return *this; }
	this_type& operator --() { ++ptr; return *this; }
	this_type  operator ++(int) { this_type temp(*this); --ptr; return temp; }
	this_type  operator --(int) { this_type temp(*this); ++ptr; return temp; }

	this_type  operator + ( difference_type i ) const { return this_type(ptr - i); }
	this_type  operator - ( difference_type i ) const { return this_type(ptr + i); }
	this_type& operator +=( difference_type i )	{ ptr -= i; return *this; }
	this_type& operator -=( difference_type i )	{ ptr += i; return *this; }

protected:
	T ptr;

};


//difference between two iterators of different pointer const-ness
template <class T1, class T2> inline
	ptrdiff_t operator -( const reverse_iterator<T1>& a, const reverse_iterator<T2>& b )
	{
		return b.base() - a.base();
	}

template <class T1, class T2> inline
	ptrdiff_t operator +( const reverse_iterator<T1>& a, const reverse_iterator<T2>& b )
	{
		return b.base() + a.base();
	}

template <class T> inline
	reverse_iterator<T> operator -( ptrdiff_t i, const reverse_iterator<T>& x )
	{
		return x.base() + i;
	}

template <class T> inline
	reverse_iterator<T> operator +( ptrdiff_t i, const reverse_iterator<T>& x )
	{
		return x.base() - i;
	}

template <class T1, class T2> inline
	bool operator ==( const reverse_iterator<T1>& a, const reverse_iterator<T2>& b )
	{
		return a.base() == b.base();
	}

template <class T1, class T2> inline
	bool operator !=( const reverse_iterator<T1>& a, const reverse_iterator<T2>& b )
	{
		return a.base() != b.base();
	}

template <class T1, class T2> inline
	bool operator <( const reverse_iterator<T1>& a, const reverse_iterator<T2>& b )
	{
		return a.base() < b.base();
	}

template <class T1, class T2> inline
	bool operator >( const reverse_iterator<T1>& a, const reverse_iterator<T2>& b )
	{
		return a.base() > b.base();
	}

template <class T1, class T2> inline
	bool operator <=( const reverse_iterator<T1>& a, const reverse_iterator<T2>& b )
	{
		return a.base() <= b.base();
	}

template <class T1, class T2> inline
	bool operator >=( const reverse_iterator<T1>& a, const reverse_iterator<T2>& b )
	{
		return a.base() >= b.base();
	}




template <class Container>
class back_insert_iterator
{
public:
	typedef std::output_iterator_tag				iterator_category;
	typedef output_iterator_tag						iterator_type;
	typedef back_insert_iterator<Container>			this_type;
	typedef Container								container_type;
	typedef typename Container::value_type			value_type;
	typedef typename Container::pointer				pointer;
	typedef typename Container::reference			reference;
	typedef typename Container::const_reference		const_reference;

	back_insert_iterator() : ptr() {}
	explicit back_insert_iterator( Container& c ) : ptr(&c) {}

	this_type& operator =( const_reference value )
	{
		ptr->push_back(value);
		return *this;
	}

	this_type& operator*() { return *this; }
	this_type& operator ++() { return *this; }
	this_type  operator ++(int) { return *this; }

protected:
	Container* ptr;

};


// back_inserter
template <class Container>
	back_insert_iterator<Container> back_inserter( Container& c )
	{
		return back_insert_iterator<Container>(c);
	}



template <class Container>
class front_insert_iterator
{
public:
	typedef std::output_iterator_tag				iterator_category;
	typedef output_iterator_tag						iterator_type;
	typedef front_insert_iterator<Container>		this_type;
	typedef Container								container_type;
	typedef typename Container::value_type			value_type;
	typedef typename Container::pointer				pointer;
	typedef typename Container::reference			reference;
	typedef typename Container::const_reference		const_reference;

	front_insert_iterator() : ptr() {}
	explicit front_insert_iterator( Container& c ) : ptr(&c) {}

	this_type& operator =( const_reference value )
	{
		ptr->push_front(value);
		return *this;
	}

	this_type& operator*() { return *this; }
	this_type& operator ++() { return *this; }
	this_type  operator ++(int) { return *this; }

protected:
	Container* ptr;

};


// front_inserter
template <class Container>
	front_insert_iterator<Container> front_inserter( Container& c )
	{
		return front_insert_iterator<Container>(c);
	}


template <class Container>
class insert_iterator
{
public:
	typedef std::output_iterator_tag				iterator_category;
	typedef output_iterator_tag						iterator_type;
	typedef insert_iterator<Container>				this_type;
	typedef Container								container_type;
	typedef typename Container::value_type			value_type;
	typedef typename Container::pointer				pointer;
	typedef typename Container::iterator			iterator;
	typedef typename Container::reference			reference;
	typedef typename Container::const_reference		const_reference;

	insert_iterator() : ptr() {}
	explicit insert_iterator( Container& c, iterator i ) : ptr(&c), it(i) {}

	this_type& operator =( const_reference value )
	{
		it = ptr->insert(it, value);
		++it;
		return *this;
	}

	this_type& operator*() { return *this; }
	this_type& operator ++() { return *this; }
	this_type  operator ++(int) { return *this; }

protected:
	Container* ptr;
	iterator it;

};


// front_inserter
template <class Container, class Iterator>
	insert_iterator<Container> inserter( Container& c, Iterator pos )
	{
		return insert_iterator<Container>(c, pos);
	}


FC_NAMESPACE_END
